package analisis.matrizContingencia;

import graphs.GraphADT;
import java.util.ArrayList;
import java.util.List;

/**
 * @file MatrizContingencia.java
 * @author Juan Humanes Ferrer
 * @date 04-Marzo-2014
 */
public final class MatrizContingencia {

    //Lista de los valores estadísticos
    private List<IMedida> listaMedidas;

    //Atributos de la matriz de contingencia
    private double tp;//ciertos positivos
    private double tn;//ciertos negativos
    private double fp;//falsos positivos
    private double fn;//falsos negativos

    /**
     * Clase utilizada para calcular la matriz de contingencia y todas las
     * medidas.
     */
    public MatrizContingencia() {
        //Valores estadísticos 
        IMedida precision = new Precision();
        IMedida recall = new Recall();
        IMedida specificity = new Specificity();
        IMedida fmeasure = new FMeasure();
        IMedida fscore = new FScore();
        IMedida falsePositiveRate = new FalsePositiveRate();
        IMedida jaccardSimilarity = new JaccardSimilarity();
        IMedida segmentationAccuracy = new SegmentationAccuracy();
        IMedida meanError = new MeanError();

        //Se añaden a la lista todas las medidas
        listaMedidas = new ArrayList<>();
        listaMedidas.add(precision); //Posicion 0
        listaMedidas.add(recall); //Posicion 1
        listaMedidas.add(fmeasure); //Posicion 2
        listaMedidas.add(meanError); //Posicion 3
        listaMedidas.add(jaccardSimilarity); //Posicion 4       
        listaMedidas.add(fscore); //Posicion 5
        listaMedidas.add(specificity); //Posicion 6
        listaMedidas.add(falsePositiveRate); //Posicion 7
        listaMedidas.add(segmentationAccuracy); //Posicion 8

        //Atributos de la matriz de contingencia
        setTp(0);//ciertos positivos
        setTn(0);//ciertos negativos
        setFp(0);//falsos positivos
        setFn(0);//falsos negativos
    }

    /**
     * Método que retorna la lista de medidas
     *
     * @return listaMedidas
     */
    public List<IMedida> getListaMedidas() {
        return listaMedidas;
    }

    /**
     * Métodod que modifica el valor de listaMedidas
     *
     * @param listaMedidas
     */
    public void setListaMedidas(List<IMedida> listaMedidas) {
        this.listaMedidas = listaMedidas;
    }

    /**
     * Método que retorna los ciertos positivos
     *
     * @return tp
     */
    public double getTp() {
        return tp;
    }

    /**
     * Métodod que modifica el valor de tp
     *
     * @param tp
     */
    public void setTp(double tp) {
        this.tp = tp;
    }

    /**
     * Método que retorna los ciertos negativos
     *
     * @return tn
     */
    public double getTn() {
        return tn;
    }

    /**
     * Métodod que modifica el valor de tn
     *
     * @param tn
     */
    public void setTn(double tn) {
        this.tn = tn;
    }

    /**
     * Método que retorna los falsos positivos
     *
     * @return fp
     */
    public double getFp() {
        return fp;
    }

    /**
     * Métodod que modifica el valor de fp
     *
     * @param fp
     */
    public void setFp(double fp) {
        this.fp = fp;
    }

    /**
     * Método que retorna los falsos negativos
     *
     * @return fn
     */
    public double getFn() {
        return fn;
    }

    /**
     * Métodod que modifica el valor de fn
     *
     * @param fn
     */
    public void setFn(double fn) {
        this.fn = fn;
    }

    /**
     * Metodo que retorna una lista de tipo Double con todos los valores de las
     * medidas recibiendo como parámetros dos grafos para compararlos. Se
     * escarga de calcular la matriz de contingencia y todas las medidas
     * necesarias.
     *
     * @param grafoUno
     * @param grafoDos
     * @return listaValores
     */
    public List<Double> matrizCont(GraphADT grafoUno, GraphADT grafoDos) {

        //Lista y matriz del primer grafo
        List<String> listaVerticesUno = grafoUno.getVertices();
        boolean[][] matrizUno = grafoUno.getAdjMatrix();
        int tamUno = matrizUno.length;

        //Lista y matriz del segundo grafo
        List<String> listaVerticesDos = grafoDos.getVertices();
        boolean[][] matrizDos = grafoDos.getAdjMatrix();

        for (int i = 0; i < tamUno; i++) {
            for (int j = i + 1; j < tamUno; j++) {

                String nodo1 = listaVerticesUno.get(i);
                String nodo2 = listaVerticesUno.get(j);

                //Se obtiene la posicion de los nodos de la listaUno, en la listaDos
                int posNodo1 = listaVerticesDos.indexOf(nodo1);
                int posNodo2 = listaVerticesDos.indexOf(nodo2);

                if (matrizUno[j][i] == true) {
                    if (posNodo1 != -1 && posNodo2 != -1) {

                        if (matrizDos[posNodo2][posNodo1] == true) {
                            setTp(getTp() + 1.0);
                        } else {
                            setFp(getFp() + 1.0);
                        }
                    } else {
                        setFp(getFp() + 1.0);
                    }
                } else {
                    if (posNodo1 != -1 && posNodo2 != -1) {

                        if (matrizDos[posNodo2][posNodo1] == true) {
                            setFn(getFn() + 1.0);
                        } else {
                            setTn(getTn() + 1.0);
                        }
                    } else {
                        setTn(getTn() + 1.0);
                    }
                }
            }
        }

        //Se crea una lista de tipo double la cual sera retornada
        List<Double> listaResult = new ArrayList<>();

        for (int i = 0; i < getListaMedidas().size(); i++) {
            getListaMedidas().get(i).calculaMedida(getTp(), getTn(), getFp(), getFn(), getListaMedidas());
            listaResult.add(getListaMedidas().get(i).verValor());
        }

        return listaResult;

    }
}
